package com.mldong.modules.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mldong.base.CommonPage;
import com.mldong.base.YesNoEnum;
import com.mldong.modules.sys.dto.DeptPageParam;
import com.mldong.modules.sys.dto.DeptParam;
import com.mldong.modules.sys.entity.Dept;
import com.mldong.modules.sys.mapper.DeptMapper;
import com.mldong.modules.sys.service.DeptService;
import com.mldong.modules.sys.vo.DeptVO;
import com.mldong.tree.IRecursionTree;
import com.mldong.tree.TreeTool;
import com.mldong.util.LowCodeServiceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * 部门 服务实现类
 * </p>
 *
 * @author mldong
 * @since 2023-09-21
 */
@Service
@RequiredArgsConstructor
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {
    private final RedisTemplate<String,String> redisTemplate;
    private static final String CACHE_KEY = "sys_dept:list";
    @PostConstruct
    public void init(){
        getDeptListInCache();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(DeptParam param) {
        param.setId(null);
        LowCodeServiceUtil.checkUnique(baseMapper,"code",param.getCode(),null,"唯一编码已存在，请检查code参数");
        Dept dept = new Dept();
        BeanUtil.copyProperties(param, dept);
        // 根据parentId查询排序值最大的排序值
        List<Dept> childDeptList = baseMapper.selectList(
                Wrappers.lambdaQuery(Dept.class)
                        .eq(Dept::getParentId,param.getParentId())
                        .orderByDesc(Dept::getSort)
                        .last("limit 1")
        );
        if(CollectionUtil.isNotEmpty(childDeptList)){
            dept.setSort(childDeptList.get(0).getSort()+1000L);
        }
        boolean success = super.save(dept);
        if(success && CollectionUtil.isEmpty(childDeptList)){
            // 如果没有子部门，则自动排序
            SpringUtil.getBean(DeptService.class).autoSort();
        }
        if(success && CollectionUtil.isNotEmpty(childDeptList)){
            redisTemplate.delete(CACHE_KEY);
        }
        return success;
    }

    @Override
    public boolean update(DeptParam param) {
        Dept dept = new Dept();
        LowCodeServiceUtil.checkUnique(baseMapper,"code",param.getCode(),param.getId(),"唯一编码已存在，请检查code参数");
        BeanUtil.copyProperties(param, dept);
        boolean success = LowCodeServiceUtil.updateById(baseMapper,dept,
                CollectionUtil.newArrayList("mainLeaderId","leaderIds"),
                true);
        if(success){
            redisTemplate.delete(CACHE_KEY);
        }
        return success;
    }
    @Override
    public boolean removeBatchByIds(Collection<?> list) {
        boolean success = super.removeBatchByIds(list);
        if(success){
            // 删除缓存
            redisTemplate.delete(CACHE_KEY);
        }
        return success;
    }
    @Override
    public CommonPage<DeptVO> page(DeptPageParam param) {
        IPage<DeptVO> page = param.buildMpPage();
        QueryWrapper queryWrapper = param.buildQueryWrapper();
        queryWrapper.eq("t.is_deleted",YesNoEnum.NO);
        List<DeptVO> list = baseMapper.selectCustom(page, queryWrapper);
        page.setRecords(list);
        return CommonPage.toPage(page);
    }
    @Override
    public DeptVO findById(Long id) {
        return baseMapper.findById(id);
    }
    @Override
    public List<DeptVO> tree(DeptPageParam param) {
        QueryWrapper queryWrapper = param.buildQueryWrapper();
        queryWrapper.orderByAsc("sort");
        List<Dept> list = this.list(queryWrapper);
        List<DeptVO> treeData = TreeTool.listToTree(BeanUtil.copyToList(list,DeptVO.class),0L,DeptVO.class);
        return treeData;
    }

    @Override
    public DeptVO getInCache(Long id) {
        return findById(id);
    }

    @Override
    public void autoSort() {
        List<Dept> list = this.list();
        List<Dept> treeData = TreeTool.listToTree(list, 0L, Dept.class);
        /**
         * 排序规则
         * 1.层级越深，排序值越大
         * 2.同级之间也要有间隔（至少 1000）
         * 3.不同层级之间间隔为 10000
         */

        Dict context = Dict.create()
            .set("levelStep", 10000)
            .set("sameLevelStep", 1000)
            .set("currentLevel", 1); // 初始层级为 1

        List<Dept> updateList = new ArrayList<>();

        TreeTool.recursion(treeData, new IRecursionTree<Dept, Dict>() {

            @Override
            public void rowHandleBefore(Dept dept, Dict res) {
                int currentLevel = res.getInt("currentLevel");
                int levelStep = res.getInt("levelStep");
                int sameLevelStep = res.getInt("sameLevelStep");

                // 获取或初始化该层级下的节点计数器
                String counterKey = "counter_level_" + currentLevel;
                int index = res.get(counterKey, 0);

                // 计算排序值
                int sortValue = levelStep * currentLevel + sameLevelStep * index;

                // 设置排序值并加入更新列表
                dept.setSort((long) sortValue);
                Dept updateDept = new Dept();
                updateDept.setId(dept.getId());
                updateDept.setSort(dept.getSort());
                updateList.add(updateDept);

                // 更新计数器
                res.put(counterKey, index + 1);

                // 进入下一层前增加层级
                res.put("currentLevel", currentLevel + 1);
            }

            @Override
            public void rowHandleAfter(Dept dept, Dict res) {
                // 回溯到上一层时减少层级
                int currentLevel = res.getInt("currentLevel");
                res.put("currentLevel", currentLevel - 1);
            }
        }, context);

        updateBatchById(updateList);
        redisTemplate.delete(CACHE_KEY);
    }

    @Override
    public void updateSort(List<DeptParam> list) {
        if(CollectionUtil.isNotEmpty(list)){
            List<Dept> updateList = list.stream().map(dept -> {
                Dept updateDept = new Dept();
                updateDept.setId(dept.getId());
                updateDept.setSort(dept.getSort());
                return updateDept;
            }).collect(Collectors.toList());
            updateBatchById(updateList);
        }
        redisTemplate.delete(CACHE_KEY);
    }

    @Override
    public List<Long> getAllSubDeptIds(Long parentId) {
        // 1. 从缓存中获取部门列表
        List<Dept> deptList = getDeptListInCache();
        // 这是子孙部门id集合
        List<Long> subDeptIds = new ArrayList<>();
        // 转换成树结构
        List<Dept> treeData = TreeTool.listToTree(deptList, parentId, Dept.class);
        // 递归获取子部门
        TreeTool.recursion(treeData, new IRecursionTree<Dept, List<Long>>() {
            @Override
            public void rowHandleBefore(Dept dept, List<Long> res) {
                res.add(dept.getId());
            }

            @Override
            public void rowHandleAfter(Dept dept, List<Long> res) {

            }
        }, subDeptIds);
        return subDeptIds;
    }

    @Override
    public List<Dept> getDeptListInCache() {
        String deptJsonData = redisTemplate.opsForValue().get(CACHE_KEY);
        List<Dept> deptList = null;
        if(StrUtil.isEmpty(deptJsonData)){
            deptList = baseMapper.selectList(Wrappers.lambdaQuery(Dept.class));
            redisTemplate.opsForValue().set(CACHE_KEY, JSONUtil.toJsonStr(deptList));
        } else {
            deptList = JSONUtil.toList(deptJsonData,Dept.class);
        }
        return deptList;
    }

}
